#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

double  res_com_time, res_sort_time, res_total_time;
struct timeval com_time_antes,com_time_depois, sort_time_antes, sort_time_depois, total_time_antes, total_time_depois; //tempos de comunicaçao entre os clientes e servidores, tempo de ordenação e tempo total, respectivamente

void error(const char *msg)
{
    perror(msg);
    exit(0);
}
//funçao de ordenação do vetor, utilizando o algoritmo bubble
void bubble(int* V,int size)
{
    int i =-1,aux;
    while (i<size-1)
    {   i++;
        if (V[i]>V[i+1])
        {
            aux = V[i];
            V[i] = V[i+1];
            V[i+1] = aux;
            i=-1;
        }

    }


}
int main(int argc, char *argv[])
{
    gettimeofday(&total_time_antes, NULL); //total_time_antes recebe o horário atual
    
    int sockfd, portno, n, vet[125],i;
    struct sockaddr_in serv_addr; //sockaddr_in : estrutura usada para conexoes na internet
				  //serv_addr: vitima
    struct hostent *server;
    srand(time(NULL)); //inicia randomizaçao pelo relogio do PC 
    for (i=0;i<125;i++)
{

        usleep(50);
	vet[i] = rand()%1000; //gera vetor com numeros aleatorios até 1000
}
    gettimeofday(&sort_time_antes, NULL); 
    bubble(vet, 125); //ordena o vetor
    gettimeofday(&sort_time_depois, NULL);  

    char buffer[256];
    //testa quantidade de argumentos passados como paramentros
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0); //Protocolo 0 -> IP
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr)); //funçãoa que escreve zeros para uma string, no nosso caso serve para zerar o resto da struct 
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);
    gettimeofday(&com_time_antes, NULL); 
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) //testa conexao
        error("ERROR connecting");
	i=0;
	while (i<125){
    bzero(buffer,256);
    sprintf(buffer,"%d",vet[i]);
    printf("\n%s",buffer);
    usleep(50);
    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0) 
         error("ERROR writing to socket");
    bzero(buffer,256);
i++;
	}
    close(sockfd);
    gettimeofday(&com_time_depois, NULL);  
    gettimeofday(&total_time_depois, NULL);
    
    //RESULTADOS: Diferença entre os tempos medidos dará o tempo de execução 	
    //Tempo de ordenaçao
    res_sort_time = ((double)(sort_time_depois.tv_sec - sort_time_antes.tv_sec)) + (((double)(sort_time_depois.tv_usec - sort_time_antes.tv_usec))/1000000);
    //Tempo de comunicaçao cliente e servidor
    res_com_time = ((double)(com_time_depois.tv_sec - com_time_antes.tv_sec)) + (((double)(com_time_depois.tv_usec - com_time_antes.tv_usec))/1000000);
    //Tempo total
    res_total_time = ((double)(total_time_depois.tv_sec - total_time_antes.tv_sec)) + (((double)(total_time_depois.tv_usec - total_time_antes.tv_usec))/1000000);	
    

    printf("\nTEMPOS: \n Comunication time: %0.6lf\n Sort time: %0.6lf\n Total time: %0.6lf\n", res_com_time, res_sort_time, res_total_time); 
    return 0;
}
